﻿using System.Collections;
using System.Collections.Generic;
using Kotonoha.Server.Objects.Model;
using Kotonoha.Server.UI.BadCards;
using NHibernate;
using System.Linq;

namespace Kotonoha.Server.Db.Dao {
    public class BadCardsDao : DaoBase {
        public BadCardsDao(ISession session) : base(session) {}

        /*
         * For Word w and Learning data l.
         * Learning lapse = lp
         * Learning repetition = lr
         * Learning difficulty = ld
         * Current interval length = il
         * Day passed since first repetition of word = dp
         * we have word badness as
         * wb = dp * (lp - 5 / 1.3 * lr * lr * ld) - il * ld * lr * lr
         * Rationale:
         * 
         * Bad words should be words that have lots of problems (high lp, possibly high dp) and good words have large ld, li, lr.
         * For instance, I take lr everywhere in square, because if user marked a word 4 or 5 four times a row, that word should be good.
         * */
        
        private readonly string findBadObjsQuery = "select {w.*}, " +
                           " ((julianday('now') - julianday(midates.tm))  * (l.LAPSE - 5 / 1.3 * l.REPETITION * l.REPETITION * l.DIFFICULTY)) - l.INTERVAL_LENGTH * l.DIFFICULTY * l.REPETITION * l.REPETITION as sc" +
                           " from MODEL_WORD {w}" +
                           " join MODEL_ITEM_LEARNING_DATA l on l.ID = w.REP_ID" +
                           " join (select m.WORD_ID as wid, min(e.TIME) as tm from MODEL_EVENT e join MODEL_EVENT_MARK m on e.EV_ID = m.EV_ID" +
                           " group by wid) as midates on w.WORD_ID = midates.wid" +
                           " order by sc desc" +
                           " limit :max";

        public List<BadWordProxy> listBadWords(int max) {
            ISQLQuery q = session.CreateSQLQuery(findBadObjsQuery);
            q.AddEntity("w", typeof (Word));
            q.AddScalar("sc", NHibernateUtil.Double);
            q.SetInt32("max", max);
            IList words = q.List();
            List<BadWordProxy> proxies = new List<BadWordProxy>(words.Count);
            int v = 0;
            foreach (var obj in words) {
                object[] objs = (object[]) obj;
                BadWordProxy p = new BadWordProxy(objs[0] as Word);
                p.Cost = (double) objs[1];
                p.Index = ++v;
                proxies.Add(p);
            }
            return proxies;
        }
    }
}
